package com.core;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import com.core.Pager.OrderType;
import com.puman.bean.Gasstation;

@Repository("baseDao")
public class BaseDaoImpl<T> implements BaseDao<T> {

	private Class<T> entityClass;
	protected SessionFactory sessionFactory;
	@Autowired
	private JdbcTemplate jdbc;

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		this.entityClass = null;
		@SuppressWarnings("rawtypes")
		Class c = getClass();
		Type type = c.getGenericSuperclass();
		if (type instanceof ParameterizedType) {
			Type[] parameterizedType = ((ParameterizedType) type)
					.getActualTypeArguments();
			this.entityClass = (Class<T>) parameterizedType[0];
		}
	}

	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@SuppressWarnings("unchecked")
	public T get(Integer id) {
		Assert.notNull(id, "id is required");
		return (T) getSession().get(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	public T load(Integer id) {
		Assert.notNull(id, "id is required");
		return (T) getSession().load(entityClass, id);
	}

	@SuppressWarnings("unchecked")
	public List<T> get(Integer[] ids) {
		Assert.notEmpty(ids, "ids must not be empty");
		String hql = "from " + entityClass.getName()
				+ " as model where model.id in(:ids)";
		return getSession().createQuery(hql).setParameterList("ids", ids)
				.list();
	}

	@SuppressWarnings("unchecked")
	public T get(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		String hql = "from " + entityClass.getName() + " as model where model."
				+ propertyName + " = ?";
		return (T) getSession().createQuery(hql).setParameter(0, value).uniqueResult();
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> getList(Map<String, Object> propertyMap) {
		Assert.notEmpty(propertyMap, "property must not be empty");
		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName())
				.append(" as model where 1=1 ");
		Iterator<String> iterator = propertyMap.keySet().iterator();
		while (iterator.hasNext()) {
			String key = iterator.next();
			sb.append(" and model.").append(key).append(" = ")
					.append(propertyMap.get(key));
		}
		return sessionFactory.openSession().createQuery(sb.toString()).list();
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<T> getList(String hql) {
		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append("  where 1=1 ");
		sb.append(hql);
		return getSession().createQuery(sb.toString()).list();
	}
	@SuppressWarnings("unchecked")
	@Override
	public List<T> getListLike(Map<String, Object> propertyMap) {

		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName())
				.append(" as model where 1=1 ");
		if (propertyMap == null || propertyMap.size() < 1) {

		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and model.").append(key).append(" like '%")
						.append(propertyMap.get(key)).append("%'");
			}
		}
		return getSession().createQuery(sb.toString()).list();
	}
	public List<T> getListLike(Map<String, Object> propertyMap,Map<String, Object> map) {

		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName())
				.append(" as model where 1=1 ");
		if (propertyMap == null || propertyMap.size() < 1) {

		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and model.").append(key).append(" like '%")
						.append(propertyMap.get(key)).append("%'");
			}
			Iterator<String> iterator1 = map.keySet().iterator();
			while (iterator1.hasNext()) {
				String key = iterator1.next();
				sb.append(" and model.").append(key).append(" like '%")
						.append(map.get(key)).append("%'");
			}
		}
		return getSession().createQuery(sb.toString()).list();
	}
	@SuppressWarnings("unchecked")
	public List<T> getList(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		String hql = "from " + entityClass.getName() + " as model where model."
				+ propertyName + " = "+value;
		return getSession().createQuery(hql).list();
	}

	@SuppressWarnings("unchecked")
	public List<T> getAll() {
		String hql = "from " + entityClass.getName();
		return getSession().createQuery(hql).list();
	}

	public Long getTotalCount() {
		String hql = "select count(*) from " + entityClass.getName();
		return (Long) getSession().createQuery(hql).uniqueResult();
	}

	public Long getTotalCountLike(Map<String, Object> propertyMap) {
		StringBuffer sb = new StringBuffer();
		sb.append(" select count(*) from ").append(entityClass.getName())
				.append(" where 1=1 ");

		if (propertyMap == null || propertyMap.size()<1) {
			
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" like '%")
						.append(propertyMap.get(key)).append("%'");

			}
		}
		return (Long) getSession().createQuery(sb.toString()).uniqueResult();
	}
	public Long getTotalCountLike(Map<String, Object> propertyMap,Map<String, Object> map) {
		StringBuffer sb = new StringBuffer();
		sb.append(" select count(*) from ").append(entityClass.getName())
				.append(" where 1=1 ");

		 if(propertyMap!=null && propertyMap.size()>0) {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" like '%")
						.append(propertyMap.get(key)).append("%'");

			}
		 }
		 if(map !=null && map.size()>0){
			Iterator<String> iterator1 = map.keySet().iterator();
			while (iterator1.hasNext()) {
				String key = iterator1.next();
				sb.append(" and ").append(key).append(" = '")
						.append(map.get(key)).append("'");

			}
		 }
		return (Long) getSession().createQuery(sb.toString()).uniqueResult();
	}
	public Long getTotalCountEqual(Map<String, Object> propertyMap) {
		StringBuffer sb = new StringBuffer();
		sb.append(" select count(*) from ").append(entityClass.getName())
				.append(" where 1=1 ");

		if (propertyMap == null || propertyMap.size()<1) {
			
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" = '")
						.append(propertyMap.get(key)).append("'");

			}
		}
		return (Long) getSession().createQuery(sb.toString()).uniqueResult();
	}
	public boolean isUnique(String propertyName, Object oldValue,
			Object newValue) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(newValue, "newValue is required");
		if (newValue == oldValue || newValue.equals(oldValue)) {
			return true;
		}
		if (newValue instanceof String) {
			if (oldValue != null
					&& StringUtils.equalsIgnoreCase((String) oldValue,
							(String) newValue)) {
				return true;
			}
		}
		System.err.println(propertyName + "---" + newValue);
		T object = get(propertyName, newValue);
		System.err.println(object == null);
		return (object == null);
	}

	public boolean isExist(String propertyName, Object value) {
		Assert.hasText(propertyName, "propertyName must not be empty");
		Assert.notNull(value, "value is required");
		T object = get(propertyName, value);
		return (object != null);
	}

	public Integer save(T entity) {
		Assert.notNull(entity, "entity is required");
		return (Integer) getSession().save(entity);
	}
	@Override
	public String add(T entity) {
		Assert.notNull(entity, "entity is required");
		return getSession().save(entity).toString();
	}

	public void update(T entity) {
		Assert.notNull(entity, "entity is required");
		getSession().update(entity);
		getSession().flush();
	}

	public void delete(T entity) {
		Assert.notNull(entity, "entity is required");
		getSession().delete(entity);
		getSession().flush();
	}

	public void delete(Integer id) {
		Assert.notNull(id, "id is required");
		T entity = load(id);
		getSession().delete(entity);
		getSession().flush();
	}

	public void delete(Integer[] ids) {
		Assert.notEmpty(ids, "ids must not be empty");
		for (Integer id : ids) {
			T entity = load(id);
			getSession().delete(entity);
		}
		getSession().flush();
	}

	public void flush() {
		getSession().flush();
	}

	public void clear() {
		getSession().clear();
	}

	public void evict(Object object) {
		Assert.notNull(object, "object is required");
		getSession().evict(object);
	}

	@Override
	public Pager findByPagerLike(Pager pager, Map<String, Object> propertyMap) {
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();

		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append(" where 1=1 ");
		if (propertyMap == null) {
			sb.append(" and 1=1 ");
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" like '%")
						.append(propertyMap.get(key)).append("%'");

			}
			if (StringUtils.isNotBlank(orderBy) && orderType != null) {
				sb.append(" order by ").append(orderBy).append(" ");
				if (orderType == OrderType.asc) {
					sb.append("ASC");
				} else {
					sb.append("DESC");
				}
			}
			Long temp = getTotalCountLike(propertyMap);
			Integer totalCount = 0;
			if (temp != null) {
				totalCount = Integer.parseInt(temp + "");
			}
			Query query = getSession().createQuery(sb.toString());
			query.setFirstResult((pageNumber - 1) * pageSize);
			query.setMaxResults(pageSize);
			@SuppressWarnings("unchecked")
			List<T> list = query.list();
			pager.setList(list);
			pager.setTotalCount(totalCount);
		}
		return pager;
	}
	@Override
	public Pager findByPagerLike(Pager pager, Map<String, Object> propertyMap,
			Map<String, Object> map) {
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();

		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append(" where 1=1 ");
		if (propertyMap == null ) {
			sb.append(" and 1=1 ");
		} else{
			if(propertyMap.size()>0){
				Iterator<String> iterator = propertyMap.keySet().iterator();
				while (iterator.hasNext()) {
					String key = iterator.next();
					sb.append(" and ").append(key).append(" like '%")
							.append(propertyMap.get(key)).append("%'");

				}
			}
		}
		if(map ==null){
			sb.append(" and 1=1 ");
		}else{
			if(map.size()>0){
				Iterator<String> iterator1 = map.keySet().iterator();
				while (iterator1.hasNext()) {
					String key = iterator1.next();
					sb.append(" and ").append(key).append(" = '")
							.append(map.get(key)).append("'");

				}
			}
		}
			
			if (StringUtils.isNotBlank(orderBy) && orderType != null) {
				sb.append(" order by ").append(orderBy).append(" ");
				if (orderType == OrderType.asc) {
					sb.append("ASC");
				} else {
					sb.append("DESC");
				}
			Long temp = getTotalCountLike(propertyMap,map);
			Integer totalCount = 0;
			if (temp != null) {
				totalCount = Integer.parseInt(temp + "");
			}
			//System.out.println(sb.toString());
			Query query = getSession().createQuery(sb.toString());
			query.setFirstResult((pageNumber - 1) * pageSize);
			query.setMaxResults(pageSize);
			@SuppressWarnings("unchecked")
			List<T> list = query.list();
			pager.setList(list);
			pager.setTotalCount(totalCount);
		}
		return pager;
	}
	public Pager findByPager(Pager pager) {
		if (pager == null) {
			pager = new Pager();
		}
		DetachedCriteria detachedCriteria = DetachedCriteria
				.forClass(entityClass);
		return findByPager(pager, detachedCriteria);
	}

	public Pager findByPager(Pager pager, DetachedCriteria detachedCriteria) {
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String property = pager.getProperty();
		String keyword = pager.getKeyword();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();

		Criteria criteria = detachedCriteria
				.getExecutableCriteria(getSession());
		if (StringUtils.isNotEmpty(property) && StringUtils.isNotEmpty(keyword)) {
			String propertyString = "";
			if (property.contains(".")) {
				String propertyPrefix = StringUtils.substringBefore(property,
						".");
				String propertySuffix = StringUtils.substringAfter(property,
						".");
				criteria.createAlias(propertyPrefix, "model");
				propertyString = "model." + propertySuffix;
			} else {
				propertyString = property;
			}
			criteria.add(Restrictions.like(propertyString, "%" + keyword
					+ "%"));
		}

		Integer totalCount = (Integer) criteria.setProjection(
				Projections.rowCount()).uniqueResult();

		criteria.setProjection(null);
		criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
		criteria.setFirstResult((pageNumber - 1) * pageSize);
		criteria.setMaxResults(pageSize);
		if (StringUtils.isNotEmpty(orderBy) && orderType != null) {
			if (orderType == OrderType.asc) {
				criteria.addOrder(Order.asc(orderBy));
			} else {
				criteria.addOrder(Order.desc(orderBy));
			}
		}
		pager.setTotalCount(totalCount);
		pager.setList(criteria.list());
		return pager;
	}

	@Override
	public Pager findByPagerEquel(Pager pager, Map<String, Object> propertyMap) {
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();

		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append(" where 1=1 ");
		if (propertyMap == null) {
			sb.append(" and 1=1 ");
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" = '")
						.append(propertyMap.get(key)).append("'");

			}
			if (StringUtils.isNotBlank(orderBy) && orderType != null) {
				sb.append(" order by ").append(orderBy).append(" ");
				if (orderType == OrderType.asc) {
					sb.append("ASC");
				} else {
					sb.append("DESC");
				}
			}
			Long temp = getTotalCountEqual(propertyMap);
			Integer totalCount = 0;
			if (temp != null) {
				totalCount = Integer.parseInt(temp + "");
			}
			Query query = getSession().createQuery(sb.toString());
			System.out.println(pageNumber+"..."+pageSize);
			query.setFirstResult((pageNumber - 1) * pageSize);
			query.setMaxResults(pageSize);
			@SuppressWarnings("unchecked")
			List<T> list = query.list();
			pager.setList(list);
			pager.setTotalCount(totalCount);
		}
		return pager;
	}

	@Override
	public Pager findByPagerEquel(Pager pager, Map<String, Object> propertyMap,
			String operation, String date) {
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();
		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append(" where 1=1 ");
		if (propertyMap == null) {
			sb.append(" and 1=1 ");
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" = '")
						.append(propertyMap.get(key)).append("'");
			}
			if(date!=null && date.length()>0){
				sb.append(" and ").append(" create_date ").append(operation).append("'").append(date).append("'");
			}
			if (StringUtils.isNotBlank(orderBy) && orderType != null) {
				sb.append(" order by ").append(orderBy).append(" ");
				if (orderType == OrderType.asc) {
					sb.append("ASC");
				} else {
					sb.append("DESC");
				}
			}
			Long temp = getTotalCountEqual(propertyMap);
			Integer totalCount = 0;
			if (temp != null) {
				totalCount = Integer.parseInt(temp + "");
			}
			Query query = getSession().createQuery(sb.toString());
			query.setFirstResult((pageNumber - 1) * pageSize);
			query.setMaxResults(pageSize);
			@SuppressWarnings("unchecked")
			List<T> list = query.list();
			pager.setList(list);
			pager.setTotalCount(totalCount);
		}
		return pager;
	}

	@Override
	public Pager findByPagerEquel(Pager pager, Map<String, Object> propertyMap,
			String operation1, String date1, String operation2, String date2) {
		
		if (pager == null) {
			pager = new Pager();
		}
		Integer pageNumber = pager.getPageNumber();
		Integer pageSize = pager.getPageSize();
		String orderBy = pager.getOrderBy();
		OrderType orderType = pager.getOrderType();
		StringBuffer sb = new StringBuffer();
		sb.append(" from ").append(entityClass.getName()).append(" where 1=1 ");
		if (propertyMap == null) {
			sb.append(" and 1=1 ");
		} else {
			Iterator<String> iterator = propertyMap.keySet().iterator();
			while (iterator.hasNext()) {
				String key = iterator.next();
				sb.append(" and ").append(key).append(" = '")
						.append(propertyMap.get(key)).append("'");
			}
			if(date1!=null && date1.length()>0 ){
				sb.append(" and ").append(" create_date ").append(operation1).append("'").append(date1).append("'");
				//append("'  add ").append("  create_date ").append(operation2).append("'").append(date2).append("'");
			}
			if(date2!=null &&date2.length()>0){
				sb.append(" and ").append(" create_date ").append(operation2).append("'").append(date2).append("'");
			}
			if (StringUtils.isNotBlank(orderBy) && orderType != null) {
				sb.append(" order by ").append(orderBy).append(" ");
				if (orderType == OrderType.asc) {
					sb.append("ASC");
				} else {
					sb.append("DESC");
				}
			}
			Long temp = getTotalCountEqual(propertyMap);
			Integer totalCount = 0;
			if (temp != null) {
				totalCount = Integer.parseInt(temp + "");
			}
			Query query = getSession().createQuery(sb.toString());
			query.setFirstResult((pageNumber - 1) * pageSize);
			query.setMaxResults(pageSize);
			@SuppressWarnings("unchecked")
			List<T> list = query.list();
			pager.setList(list);
			pager.setTotalCount(totalCount);
		}
		return pager;
	}


}